﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using Citi.Helpers;
using Citi.RoutineBase;
using OfficeOpenXml;
using System.Threading;

namespace Citi.PTSConsolidation.SchedulerUI
{
    public abstract class MonthlyReportGeneration
    {
        internal abstract List<string> ColumnsToMerge { get; }
        internal abstract List<string> ColumnsToDate { get; }
        internal string ReportPath { get; set; }
        internal abstract string ReportName { get; }
        internal string FriendlyName { get; set; }
        internal abstract string TemplatePath { get; }
        internal abstract string MonthlyReportWithConnections { get; }

        private string PtsReportSaveTempPath { get { return ConfigurationManager.AppSettings["PtsReportSaveTempPath"]; } }
        private string PtsReportSavePath { get; set; }
        private int[] Weeks { get { return new[] { 1, 2, 3, 4, 5 }; } }

        public void GenerateReport(DateTime referenceDate, int year, ref ICurrentAction currentAction)
        {
            var reportTempPath = CopyReportMonthlyToLocal(referenceDate, year, ref currentAction);

            RefreshFile(currentAction, reportTempPath);

            //UpdateReport(reportTempPath, PtsReportSavePath, Weeks.Where(x => x >= referenceDate.GetWeekOfMonth()).Select(x => string.Concat("Week ", x)), referenceDate);
            UpdateReport(reportTempPath, PtsReportSavePath, Weeks.Select(x => string.Concat("Week ", x)), referenceDate);

            CopyOldReportsToOldFolder(referenceDate, ref currentAction);
            DeleteOldReports(referenceDate, ref currentAction);
        }

        private void RefreshFile(ICurrentAction currentAction, string reportTempPath)
        {
            currentAction.Description = string.Format("Refreshing file {0}", reportTempPath);
            ExcelHelper.RefreshAll(reportTempPath, null, false, false);

            currentAction.Description = "Removing data connections from previous weeks";
            ExcelHelper.RemoveDataLinks(reportTempPath, Weeks.Select(x => string.Concat("Week", x)).ToArray());

            currentAction.Description = "Transforming table to range";
            ExcelHelper.TransformTableToRange(reportTempPath, Weeks.Select(x => string.Concat("Week", x)).ToArray());
        }

        private void DeleteOldReports(DateTime referenceDate, ref ICurrentAction currentAction)
        {
            var oldReportsFolder = Path.Combine(ReportPath, "Old");

            if (!Directory.Exists(oldReportsFolder)) Directory.CreateDirectory(oldReportsFolder);

            var filesToDrop = Directory.GetFiles(oldReportsFolder).Where(x => GetDateFromFileName(x) <= referenceDate.AddDays(-4)).ToList();

            try
            {
                filesToDrop.ForEach(File.Delete);
            }
            catch { }
        }

        private void CopyOldReportsToOldFolder(DateTime referenceDate, ref ICurrentAction currentAction)
        {
            var oldReportsFolder = Path.Combine(ReportPath, "Old");

            currentAction.Description = "Moving Previous report to Old Folder";

            var filesToMove = Directory.GetFiles(ReportPath).Where(x => GetDateFromFileName(x) < referenceDate
                && GetDateFromFileName(x).Month == referenceDate.Month
                && !Path.GetFileNameWithoutExtension(x).EndsWith(referenceDate.ToString("yyyyMMdd"))).ToList();

            try
            {
                filesToMove.ForEach(x =>
                {
                    File.Copy(x, Path.Combine(oldReportsFolder, Path.GetFileName(x)), true);
                    File.Delete(x);
                });
            }
            catch { }
        }

        private static DateTime GetDateFromFileName(string file)
        {
            try
            {
                var date = Path.GetFileNameWithoutExtension(file).Split('_').Last();

                string formatString = "yyyyMMdd";
                DateTime dateParsed;

                if (DateTime.TryParseExact(date, formatString, null, System.Globalization.DateTimeStyles.None, out dateParsed))
                    return dateParsed;
                else
                    return DateTime.MinValue;
            }
            catch
            {
                return DateTime.MinValue;
            }
        }

        private string CopyReportMonthlyToLocal(DateTime referenceDate, int year, ref ICurrentAction currentAction)
        {
            //var monthlyReportWithConnections = string.Format(MonthlyReportWithConnections, year, referenceDate.ToString("yyyyMM"));

            var reportExcel = "{0}{1}_{2}.xlsx";
            var fileName = string.Format(reportExcel, ReportName, string.Concat(year, referenceDate.ToString("MM")), referenceDate.ToString("yyyyMMdd"));
            var reportTempPath = Path.Combine(PtsReportSaveTempPath, fileName);

            if (!Directory.Exists(ReportPath))
                Directory.CreateDirectory(ReportPath);

            PtsReportSavePath = Path.Combine(ReportPath, fileName);

            var currentWeek = referenceDate.GetWeekOfMonth();

            //if (File.Exists(monthlyReportWithConnections))
            //    File.Copy(monthlyReportWithConnections, reportTempPath, true);
            //else
            //{
            var reportType = year - referenceDate.Year == 0
                        ? "CurrentYear"
                        : year - referenceDate.Year == 1
                            ? "NextYear"
                            : "PreviousYear";
            File.Copy(string.Format(TemplatePath, reportType), reportTempPath, true);
            //}

            //if (currentWeek > 1)
            //{
            //    currentAction.Description = "Removing data connections from previous weeks";
            //    ExcelHelper.RemoveDataLinks(reportTempPath, Weeks.Where(x => x < currentWeek).Select(x => string.Concat("Week", x)).ToArray());

            //    currentAction.Description = "Transforming table to range";
            //    ExcelHelper.TransformTableToRange(reportTempPath, Weeks.Where(x => x < currentWeek).Select(x => string.Concat("Week", x)).ToArray());

            //    currentAction.Description = "Merging header and inserting date in the first row";
            //    UpdateReport(reportTempPath, reportTempPath, Weeks.Where(x => x < currentWeek).Select(x => string.Concat("Week ", x)), referenceDate);

            //    File.Copy(reportTempPath, monthlyReportWithConnections, true);
            //}

            currentAction.Description = "File copied to temp folder";

            return reportTempPath;
        }

        private void UpdateReport(string reportTempPath, string reportFinalPath, IEnumerable<string> sheetsName, DateTime referenceDate)
        {
            using (var excelPackage = new ExcelPackage(new FileInfo(reportTempPath), true))
            {
                var worksheets = excelPackage.Workbook.Worksheets.Where(x => sheetsName.Contains(x.Name));
                var currentMonday = referenceDate.AddDays(-(((int)referenceDate.DayOfWeek) - 1));

                foreach (var worksheet in worksheets)
                {
                    var monday = currentMonday.AddDays((int.Parse(worksheet.Name.Replace("Week ", string.Empty)) - currentMonday.GetWeekOfMonth()) * 7);

                    foreach (var column in ColumnsToMerge)
                    {
                        var text = worksheet.Cells[string.Format("{0}2", column)].Value;
                        worksheet.Cells[string.Format("{0}1:{0}2", column)].Merge = true;
                        worksheet.Cells[string.Format("{0}1", column)].Value = text;
                    }

                    foreach (var column in ColumnsToDate)
                    {
                        DateTime date;

                        switch (ColumnsToDate.IndexOf(column))
                        {
                            case 0:
                                date = monday.AddDays(-3);
                                break;
                            case 1:
                                date = monday;
                                break;
                            default:
                                date = monday.AddDays(ColumnsToDate.IndexOf(column) - 1);
                                break;
                        }

                        worksheet.Cells[string.Format("{0}1", column)].Value = date.ToString("dd/MM/yyyy");
                    }
                }

                var bin = excelPackage.GetAsByteArray();
                File.WriteAllBytes(reportFinalPath, bin);
            }
        }
    }
}
